import { ComputedRef, onBeforeMount, onMounted, Ref, unref } from 'vue';

import { isString } from '@/utils/is';

type Change = {
  w?: number;
  s?: number;
  e?: number;
  n?: number;
};

type UseDragResizeProps = {
  uid: string;
  minW?: number;
  maxW?: number;
  minH?: number;
  maxH?: number;
  resize?: 'x' | 'y'; // 调整宽或者高，不传都可以调整
  canDrag?: boolean | Ref<boolean> | ComputedRef<boolean>;
  callback?: (change: Change) => void;
};

// 拖拽调整div大小
export const useDragResize = (config: UseDragResizeProps) => {
  const {
    uid,
    minW = 0,
    maxW = 1080,
    minH = 0,
    maxH = 1920,
    resize,
    canDrag = true,
    callback,
  } = config;
  let resizeAble = false;
  let downDir = '';
  let moveDir = '';
  // 鼠标按下时坐标
  let downX = 0;
  let downY = 0;
  let container: HTMLElement | null;
  const changeOffset: any = {};

  const registerMouseEvent = () => {
    container?.addEventListener('mousemove', mousemove);
    container?.addEventListener('mouseup', mouseup);
    container?.addEventListener('mousedown', mousedown);
    document.addEventListener('mousemove', windowMousemove);
    document.addEventListener('mouseup', mouseup);
  };

  const removeMouseEvent = () => {
    container?.removeEventListener('mousemove', mousemove);
    container?.removeEventListener('mouseup', mouseup);
    container?.removeEventListener('mousedown', mousedown);
    document.removeEventListener('mousemove', windowMousemove);
    document.removeEventListener('mouseup', mouseup);
  };

  const mouseup = () => {
    if (resizeAble) {
      callback?.(changeOffset);
    }
    resizeAble = false;
  };

  const mousedown = (e) => {
    const targetClass = e.target?.className;
    if (isString(targetClass) && targetClass.includes('dragger')) {
      resizeAble = false;
      return;
    }
    downDir = getDirection(e);
    if (downDir) {
      if (
        (resize === 'y' && ['w', 'e'].includes(downDir)) ||
        (resize === 'x' && ['n', 's'].includes(downDir))
      ) {
        return;
      }
      resizeAble = true;
      downX = e.clientX;
      downY = e.clientY;
    }
  };

  const windowMousemove = (e: MouseEvent) => {
    mousemove(e, moveDir);
  };

  const mousemove = (e: MouseEvent, dir?) => {
    if (!unref(canDrag)) return;
    if (!dir) {
      dir = getDirection(e);
      moveDir = dir;
    }

    const style = container?.style;
    if (!style) return;

    if (
      !dir ||
      (resize === 'y' && ['w', 'e'].includes(dir)) ||
      (resize === 'x' && ['n', 's'].includes(dir))
    ) {
      style.cursor = 'default';
    } else {
      style.cursor = dir + '-resize';
    }

    if (!resizeAble) return;

    const pointX = e.clientX;
    const pointY = e.clientY;

    const x = container?.offsetWidth || 0;
    const y = container?.offsetHeight || 0;

    if (downDir.includes('e')) {
      let offset = x + (pointX - downX);
      if (offset < minW) {
        offset = minW;
      } else if (offset > maxW) {
        offset = maxW;
      }
      style.width = offset + 'px';
      changeOffset.e = pointX - downX;
      downX = pointX;
    }
    if (downDir.includes('n')) {
      let offset = y + (downY - pointY);
      if (offset < minH) {
        offset = minH;
      } else if (offset > maxH) {
        offset = maxH;
      }
      style.height = offset + 'px';
      changeOffset.n = downY - pointY;
      downY = pointY;
    }
    if (downDir.includes('s')) {
      let offset = y + (pointY - downY);
      if (offset < minH) {
        offset = minH;
      } else if (offset > maxH) {
        offset = maxH;
      }
      offset = Math.max(minH, y + (pointY - downY));
      style.height = offset + 'px';
      changeOffset.s = pointY - downY;
      downY = pointY;
    }
    if (downDir.includes('w')) {
      let offset = x + (downX - pointX);
      if (offset < minW) {
        offset = minW;
      } else if (offset > maxW) {
        offset = maxW;
      }
      style.width = offset + 'px';
      changeOffset.w = downX - pointX;
      downX = pointX;
    }
    callback?.(changeOffset);
  };

  // 鼠标位于div方位
  const getDirection = (e: MouseEvent): string => {
    const { x, y } = e;
    const { top, bottom, left, right } = container!.getBoundingClientRect();
    const offset = 10;
    let dir = '';

    // 北
    if (y < top + offset) {
      dir += 'n';
    }

    // 南
    if (y > bottom - offset) {
      dir += 's';
    }

    // 西
    if (x < left + offset) {
      dir += 'w';
    }

    // 东
    if (x > right - offset) {
      dir += 'e';
    }

    return dir;
  };

  onMounted(() => {
    container = document.getElementById(uid) as HTMLElement;
    registerMouseEvent();
  });

  onBeforeMount(() => {
    removeMouseEvent();
    container = null;
  });
};
